package com.bblocks.common.anti_reptile.rule.impl;


import com.bblocks.common.anti_reptile.config.AntiReptileProperties;
import com.bblocks.common.anti_reptile.config.bean.RuleComm;
import com.bblocks.common.anti_reptile.constant.RuleResultEnum;
import com.bblocks.common.anti_reptile.constant.RuleTypeEnum;
import com.bblocks.common.anti_reptile.rateLimiter.RateLimiterPlan;
import com.bblocks.common.anti_reptile.rule.AbstractRule;
import com.bblocks.common.anti_reptile.rule.RuleData;
import com.bblocks.common.anti_reptile.service.TokenService;
import com.bblocks.common.anti_reptile.util.ServletUtils;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;

/**
 * <p>Project: bb-anti-reptile - UserRule</p>
 * <p>描述：用户访问规则
 * 目前是基于：token，存在分享， ，建议非法token直接要求登录，或者token可以安全检测如jwt方案</p>
 *
 * @Author Zhao [125043150@qq.com]
 * @Date 2024/3/23 11:43
 * @Version 1.0
 * @since 8
 */
@Slf4j
public class UserRule extends AbstractRule {
    private final RuleTypeEnum ruleType = RuleTypeEnum.USER;
    private AntiReptileProperties properties;
    private RateLimiterPlan rateLimiterPlan;
    private TokenService tokenService;


    public UserRule(RateLimiterPlan rateLimiterPlan, AntiReptileProperties properties,TokenService tokenService) {
        this.rateLimiterPlan = rateLimiterPlan;
        this.properties = properties;
        this.tokenService = tokenService;
    }

    @Override
    @SuppressWarnings("unchecked")
    protected RuleComm doMatch(HttpServletRequest request, HttpServletResponse response) {
        if(properties.getUserRule().getTokenKey() == null || properties.getUserRule().getTokenKey().isEmpty())
            return null;
        String userId = userId(request,properties.getUserRule(),tokenService);
        if(userId == null){//未登录状态
            return null;
        }

        String requestUrl = ServletUtils.getUrlWithoutParam(request);
        //毫秒，默认5000
        int expirationTime = properties.getUserRule().getExpirationTime();
        //锁定时间-秒
        long lockTime = properties.getUserRule().getLockExpire();
        //最高expirationTime时间内请求数，这个由统计渠道提取
        int requestMaxSize = -1;
        RuleResultEnum resultEnum = RuleResultEnum.getRuleResult(properties.getUserRule().getLockType());

        if(rateLimiterPlan.isBlack(ruleType,userId)) {
                log.info("Intercepted request, uri: {}, user：{}。Automatically unlock after {} seconds", requestUrl, userId,lockTime);
                return properties.getUserRule();
        }

        //String key = IP_RATELIMITER_COUNT_PREFIX.concat(AntiReptileConsts.JOINER).concat(token).concat(AntiReptileConsts.JOINER).concat(requestUrl);
        if(!rateLimiterPlan.tryAcquire(ruleType,userId,requestUrl, requestMaxSize, expirationTime, TimeUnit.MILLISECONDS)) {
            if(resultEnum.isNeedBlack()) {
                rateLimiterPlan.joinBlack(properties.getUserRule(), userId, requestUrl, lockTime, TimeUnit.SECONDS);
                if(log.isInfoEnabled())
                    log.info("Intercepted request, uri: {}, user：{}, request :{}, times in {} ms。Automatically unlock after {} seconds", requestUrl, userId, requestMaxSize, expirationTime, lockTime);
            }
            return properties.getUserRule();
        }
        return null;
    }

    @Override
    public void reset(HttpServletRequest request, String realRequestUri) {
        String token = request.getHeader(properties.getUserRule().getTokenKey());
        if(token == null || token.isEmpty()){//非登录状态
            return ;
        }
        String userId =  tokenService.token2UserId(request,token);
        if(userId == null || userId.isEmpty()){//非登录状态
            return ;
        }
        /**
         * 重置计数器,以及清除黑名单
         */
        int ret = this.resetDefault(properties.getUserRule(),rateLimiterPlan,userId);
        log.info("解除结果：{}",ret);
    }

    @Override
    public int getOrder() {
        return 4;
    }
}
